/*
 * $Id: JsonRpcError.java 63219 2007-07-24 13:22:20Z jdamick $
 *
 * Copyright 2006- Revolution Health Group.  All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Revolution Health Group.  (Confidential Information).
 * You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license 
 * agreement you entered into with Revolution Health Group.
 *
 */
package org.javason.jsonrpc;

import java.lang.reflect.InvocationTargetException;

import org.apache.log4j.Logger;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;

import org.javason.exception.JsonRpcServiceException;


public class JsonRpcError {
	private static final Logger _log = Logger.getLogger(JsonRpcError.class);
	public static final String VERSION = "$Rev: 63219 $";
	
	private static final String NAME = "JsonRpcError";
	private Integer _code; // 000 - 999
	private String _message;
	private JSONObject _error = new JSONObject();
	

	// TODO: make sure these error codes match the spec (error codes TBD)
	public enum JsonRpcErrorCode {
		SERVER_ERROR (1, "Server error"),
		PARSE_ERROR (2, "Parse error"),
		BAD_CALL (3, "Bad call"),
		MEMBER_OUT_OF_SEQ (4, "Call member out of sequence"),
		SERVICE_ERROR (5, "Service error"),
		PROC_NOT_FOUND (6, "Procedure not found");
		
		private int _code = 0;
		private String _message;
		JsonRpcErrorCode(int code, String message) { _code = code; _message = message; }
		public JsonRpcError createJsonRpcError() { return new JsonRpcError(_code, _message); }
	}
	
	
	
	public JsonRpcError() { }
	
	public JsonRpcError(Integer code, String message, Throwable exception) { 
		_code = code;
		_message = message;
		initializeError(exception);
	}
	
	public JsonRpcError(Integer code, String message) { 
		_code = code;
		_message = message;
	}
	
	public JsonRpcError(Throwable exception) { 
		initializeError(exception);
	}
	
		
	/**
	 * @return Returns the _name.
	 */
	public static String getName() {
		return NAME;
	}
	
	/**
	 * @return Returns the code.
	 */
	public Integer getCode() {
		return _code;
	}
	
	/**
	 * @param code The code to set.
	 */
	public void setCode(Integer code) {
		_code = code;
	}
	
	/**
	 * @return Returns the error.
	 */
	public JSONObject getError() {
		return _error;
	}
	
	/**
	 * @param error The error to set.
	 */
	public void setError(JSONObject error) {
		_error = error;
	}
	
	/**
	 * @param error The error to set.
	 */
	public void setError(Throwable exception) {
		initializeError(exception);
	}
	
	/**
	 * @return Returns the message.
	 */
	public String getMessage() {
		return _message;
	}
	
	/**
	 * @param message The message to set.
	 */
	public void setMessage(String message) {
		_message = message;
	}
	
	public Object toJSON() {
		
		Object error = JSONNull.getInstance();
		if (_code != null && _message != null) {
			try {
				error = new JSONObject();
				((JSONObject) error).put("name", getName());
				((JSONObject) error).put("code", getCode());
				((JSONObject) error).put("message", getMessage());
				((JSONObject) error).put("error", getError());
			} catch (JSONException jsonException) {
				_log.error("Error encoding json object", jsonException);
				error = JSONNull.getInstance();
			}
		}
		
		return error;
	}
	
	
	private void initializeError(Throwable exception) {
		Throwable errorException = null;
		if (exception instanceof InvocationTargetException) {
			errorException = ((InvocationTargetException)exception).getTargetException();
		}
		
		if (errorException == null) {
			errorException = exception;
		}
		
		try {
			_error.put("name", errorException.toString());
			
			if (errorException instanceof JsonRpcServiceException) {
				_error.put("resultCode", ((JsonRpcServiceException)errorException).getResultCode());
			}
			
			_error.put("message", errorException.getMessage());
			
			if (errorException.getCause() != null) {
				_error.put("cause", errorException.getCause().toString());
			} else {
				_error.put("cause", JSONNull.getInstance().toString());
			}
			
			JSONArray stack = new JSONArray();
			if (_log.isDebugEnabled()) {
				for (StackTraceElement stEl : errorException.getStackTrace()) {
					stack.add(stEl.toString());
				}
			}
			_error.put("stack", stack);
		} catch (JSONException jsonException) {
			_log.error("Error encoding json object", jsonException);
		}
	}
	
}
